/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef OBJECT_STORAGE_PREFIX_UTILS_H
#define OBJECT_STORAGE_PREFIX_UTILS_H
#include <string>
#include <unordered_map>
#include  <functional>
#include "CommonStruct.h"
namespace OBSPlugin {
    
    struct PrefixHash {
        size_t operator()(const PrefixInfo& p) const
        {
            const int prefixHashShift = 16777619;
            std::size_t h1 = std::hash<std::string>{}(p.bucketName);
            std::size_t h2 = std::hash<std::string>{}(p.parentPrefixFilter.empty() ? "" : p.parentPrefixFilter.front());
            std::size_t h3 = std::hash<std::string>{}(p.isPrefixLevelObject? "true" : "false");
            return (h1 * prefixHashShift) ^ h2 ^ (h3 << 1);
        }
    };
   
    bool operator==(const PrefixInfo& a, const PrefixInfo& b)
    {
        return a.buildMergeKey() == b.buildMergeKey();
    }

    void MergePrefix(PrefixInfo& dest, const PrefixInfo& toMerge)
    {
        std::vector<std::string> w;
        w.reserve(dest.subPrefixs.size() + toMerge.subPrefixs.size());
        std::merge(dest.subPrefixs.begin(), dest.subPrefixs.end(),
            toMerge.subPrefixs.begin(), toMerge.subPrefixs.end(), std::back_inserter(w));
        dest.subPrefixs = std::move(w);
    }

    template <typename T, typename F>
    std::unordered_map<PrefixInfo, PrefixInfo, PrefixHash> MergeCollection(const T& collection, F function)
    {
        std::unordered_map<PrefixInfo, PrefixInfo, PrefixHash> r;
        for (const auto& item : collection) {
            function(r[item], item);
        }
        return r;
    }
    template <typename T>
    std::vector<PrefixInfo> MergeCollection(const T& collection)
    {
        std::unordered_map<PrefixInfo, PrefixInfo, PrefixHash> merged = MergeCollection(collection, MergePrefix);
        std::vector<PrefixInfo> result;
        for (auto& kv : merged) {
            PrefixInfo prefix;
            kv.second.bucketName = kv.first.bucketName;
            kv.second.parentPrefixFilter = kv.first.parentPrefixFilter;
            kv.second.isPrefixLevelObject = kv.first.isPrefixLevelObject;
            result.emplace_back(kv.second);
        }
        return result;
    }
}
#endif